/*
 * Copyright 2011 The Rusted Roof, LLC.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package org.proteusframework.api;


import org.proteusframework.api.model.*;

import java.util.Collection;
import java.util.Set;

/**
 * Plugin registrars maintain the authoritative runtime registration database of plugin archetype instances, tracking
 * which API versions each instance supports.
 *
 * @author Tacoma Four
 */
public interface IPluginRegistrar extends INamedObject
{
    /**
     * Collection of {@link VersionedInterface} definitions supported by the plugin archetype.
     *
     * @return Version collection
     */
    IVersionCollection getVersionCollection();

    /**
     * Collection of installed versions supported by the given named plugin.
     *
     * @param qualifiedName Qualified name
     * @return Version collection
     * @throws NoSuchQualifiedNameException when no matching plugin with the given qualified name can be found
     *                                      in the registrar
     */
    IVersionCollection getVersionCollection(IQualifiedName qualifiedName) throws NoSuchQualifiedNameException;

    /**
     * Create a plugin that implements the requested version of the API regardless of plugin provider. No special
     * configuration option restrictions are placed on the factory.
     *
     * @param version           Target API version
     * @param expectedInterface Interface that the version is expected to implement
     * @return Plugin instance
     * @throws NoSuchVersionException when no matching version of the API can be found in the registrar
     */
    <T extends IPlugin> T createPlugin(IVersion version, Class<T> expectedInterface) throws NoSuchVersionException;

    /**
     * Create a plugin of the specific type at the specific version of the API, optionally defining a set of
     * further restrictions by way of a set of {@link org.proteusframework.api.config.IConfigProperty} definitions.  The
     * factory must honor the {@link org.proteusframework.api.config.IConfigProperty#isMandatory()} declaration on each
     * configuration restriction provided.
     * <p/>
     * For example, if a plugin is capable of working with a specific set of MIME types, it is possible to use this
     * overloaded version of <code>createPlugin</code> to restrict the factory, obtaining a contratual guarantee
     * that the returned plugin can support the specific MIME type. If the caller demands that the plugin instance
     * support <code>application/octet-stream</code> and defines isMandatory as true for the property, then the factory
     * <b>must</b> throw a <code>NoSuchVersionException</code> if it cannot honor the mandatory configuration
     * restriction.
     * <p/>
     * Each plugin archetype is responsible for documenting a collection of <code>IConfigProperty</code> keys that it
     * is capable of honoring. When a factory encounters an unknown key marked as mandatory, contractually the factory
     * must throw a <code>NoSuchVersionException</code>.
     *
     * @param versionDescriptor Version descriptor
     * @param expectedInterface Expected interface; must extend IPlugin
     * @return Plugin instance
     * @throws NoSuchQualifiedNameException when no matching plugin with the given qualified name can be found in
     *                                      the registrar
     * @throws NoSuchVersionException       when no matching version of the API is supported by the named plugin
     */
    <T extends IPlugin> T createPlugin(IVersionDescriptor versionDescriptor, Class<T> expectedInterface)
            throws NoSuchQualifiedNameException, NoSuchVersionException;

    /**
     * Collection of all registered plugins.
     *
     * @return Non-null, immutable collection of Proteus plugin instances. Any modifications to this collection have
     *         no impact on the authoritative collection maintained by this registrar.
     */
    Collection<IQualifiedName> qualifiedNames();

    /**
     * Collection of all supported versions offered by a specific plugin.
     *
     * @param qualifiedName Qualified name to try and locate a plugin under
     * @return Non-null, immutable collection of installed versions for the given plugin. Any modifications to this collection
     *         have no impact on the authoritative collection maintained by this registrar.
     * @throws NoSuchQualifiedNameException when no matching plugin with the given qualified name can be found
     *                                      in the registrar
     */
    Collection<IVersion> list(IQualifiedName qualifiedName) throws NoSuchQualifiedNameException;

    /**
     * Collection of all installed versions with no indication of provider.
     *
     * @return Non-null, immutable collection of versions
     */
    Set<IVersion> versions();

    /**
     * Determines if a plugin is registered under the given qualified name.
     *
     * @param qualifiedName Qualified name to try and locate a plugin under
     * @return true, if the plugin is registered
     */
    boolean isInstalled(IQualifiedName qualifiedName);

    /**
     * Determines if a plugin is registered that supports the given version.
     *
     * @param version API version the plugin must support
     * @return true, if a plugin is registered that supports the given API version
     */
    boolean isInstalled(IVersion version);

    /**
     * Determines if the given plugin version is registered under the given qualified name, at the given version.
     *
     * @param versionDescriptor Version descriptor
     * @return true, if the plugin at the given version is installed
     */
    boolean isInstalled(IVersionDescriptor versionDescriptor);
}
